package server

import (
	"context"
	"edata-hub/pkg/raft"
	raftservices "edata-hub/pkg/raft/services"
	"edata-hub/pkg/server/services"
	"encoding/json"
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/mem"
	"google.golang.org/grpc"
	"net"
	"sync"
	"time"
)

// Worker
// Worker结构体
type Worker struct {
	// worker记录的master（Leader）地址
	Master string
	Config Config
	// 存储worker的监控信息，key是时间
	Info raft.WorkerInfo
	// Worker的状态
	Role string
	// Raft日志
	Log *raft.Logs
	// 输出日志
	Msg raft.Message
	// 程序关闭信号通道
	Shutdown chan bool
	// grpc 客户端
	RaftGrpcClient raftservices.RaftServiceClient
	// grpc 服务
	GrpcServer *grpc.Server
	// grpc 监听器
	GrpcListener net.Listener
	services.UnimplementedWorkerServiceServer
	// http 服务器
	HttpServer *gin.Engine
	// 访问 worker 资源时要用到的锁
	Mutex sync.Mutex
	// 用于 goroutine 同步
	Wg sync.WaitGroup
}

const (
	DEAD      = "Dead"
	HEARTBEAT = "HEARTBEAT"
)

func (w *Worker) Initialize() {
	w.Shutdown = make(chan bool)
	w.Master = w.Config.RaftConfig.Ip + ":" + w.Config.RaftConfig.RpcPort
	//初始化 Worker 日志
	w.Log = raft.MakeEmptyLog()
	//初始化输出消息
	w.Msg = raft.Message{}
	w.Msg.PrintLevel = w.Config.WorkerConfig.MsgLevel
	//初始化 GRPC 服务对象
	listener, err := net.Listen("tcp", w.Config.WorkerConfig.Ip+":"+w.Config.WorkerConfig.RpcPort)
	if err != nil {
		w.Msg.Error("%s grpc listen fail:%s", w.Config.WorkerConfig.Ip+":"+w.Config.WorkerConfig.RpcPort, err)
	}
	w.GrpcListener = listener
	w.GrpcServer = grpc.NewServer()
	// Raft 有针对 Worker 自定义的远程RPC方法定义，只有一个，OnHandleCommand。
	// 此处将 Raft 为 Worker 定义的 RPC 方法注册给 Worker。
	// 接下来在 Worker 需要重写 Raft 给 Worker 定义的 OnHandleCommand 方法。
	services.RegisterWorkerServiceServer(w.GrpcServer, w)
	//创建rpc客户端
	w.CreateRaftGRPCClient()
	//初始化 HTTP 服务对象，配置跨域
	gin.SetMode(gin.ReleaseMode)
	w.HttpServer = gin.Default()
	w.HttpServer.SetTrustedProxies([]string{"127.0.0.1"})
	corsConfig := cors.DefaultConfig()
	corsConfig.AllowAllOrigins = true
	corsConfig.AllowMethods = []string{"GET", "POST", "PUT", "DELETE"}
	corsConfig.AllowHeaders = []string{"Accept", "Content-Type", "Content-Length", "Authorization"}
	w.HttpServer.Use(cors.New(corsConfig))
	w.InitWorkerHttpServices()
}

// 启动 Worker
func (w *Worker) StartServer() {
	//  如果注册失败，则直接退出
	w.Initialize()
	if !w.RegistToMaster() {
		return
	}
	w.Wg.Add(3)
	go w.StartTicker()
	go w.StartHttpServer()
	go w.StartGRPCServer()
	w.Wg.Wait()
}

// 启动RPC服务器
func (w *Worker) StartGRPCServer() {
	defer w.Wg.Done()
	grpcAddr := w.Config.WorkerConfig.Ip + ":" + w.Config.WorkerConfig.RpcPort
	w.Msg.Info("grpc server running at %s", grpcAddr)
	serveErr := w.GrpcServer.Serve(w.GrpcListener)
	if serveErr != nil {
		w.Msg.Error("grpc serve fail,%s", serveErr)
	}
}

// 启动Http服务器
func (w *Worker) StartHttpServer() {
	defer w.Wg.Done()
	httpAddr := w.Config.WorkerConfig.Ip + ":" + w.Config.WorkerConfig.HttpPort
	w.Msg.Info("http server running at %s", httpAddr)
	serveErr := w.HttpServer.Run(httpAddr)
	if serveErr != nil {
		w.Msg.Error("http serve fail:%s", serveErr)
	}
}

// Worker的计时器，用于定时任务，例如收集Worker所在节点的系统信息等
func (w *Worker) StartTicker() {
	defer w.Wg.Done()
	for {
		w.CollectMonitorInformation()
		nodeInfoBytes, _ := json.Marshal(w.Info)
		params := make(map[string]string)
		params["ip"] = w.Config.WorkerConfig.Ip
		params["workerInfo"] = string(nodeInfoBytes)

		req := &raftservices.CommandReq{
			Command: "WORKER_TIKTOK",
			Params:  params,
		}
		w.Msg.Info("sending tiktok to master %s", w.Master)
		stream, sendCmdErr := w.RaftGrpcClient.OnHandleCommand(context.Background(), req)
		if sendCmdErr != nil {
			w.Msg.Error("can not send command ,%s", sendCmdErr)
		}
		for {
			result, err := stream.Recv()
			if err != nil {
				break
			}
			if result.Status == -1 {
				w.Msg.Error("sending tiktok to master %s fail", w.Master)
				break
			} else if result.Status == 2 {
				break
			}
		}
		time.Sleep(time.Duration(w.Config.WorkerConfig.TicTok) * time.Second)
	}
}

// 获取当前节点的监控信息，CPU，Memory，磁盘，网络
func (w *Worker) CollectMonitorInformation() {
	memInfo, _ := mem.VirtualMemory()
	w.Info.UsedMem = int(memInfo.Total - memInfo.Available)
	w.Info.TotalMem = int(memInfo.Total)

	//获取磁盘信息
	diskInfo, _ := disk.Usage("/")
	w.Info.UsedDisk = int(diskInfo.Used)
	w.Info.TotalDisk = int(diskInfo.Total)
}

// 注册至Master
func (w *Worker) RegistToMaster() bool {
	//req := new(raft_services.CommandReq)
	//req.Command = "REGISTER_WORKER"
	//req.Params = make(map[string]string)
	//req.Params["addr"] = w.Addr
	//client := w.CreateGRPCClient(w.Master)
	//resp, err := client.OnHandleCommand(context.Background(), req)
	//if err != nil || !resp.Success {
	//	w.Msg.Error("worker %s regist to master %s fail,%s", w.Addr, w.Master, err)
	//	return false
	//}
	//w.Msg.Info("worker %s regist to master %s success", w.Addr, w.Master)
	return true
}
